﻿using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using FF14TreasureDiggingTool.DataAccess.ApplicationDbContext;
using FF14TreasureDiggingTool.DataAccess.Enums;
using FF14TreasureDiggingTool.DataAccess.Models;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Windows;
using Wpf.Ui.Common.Interfaces;
using Wpf.Ui.Controls.Interfaces;
using Wpf.Ui.Mvvm.Contracts;

namespace FF14TreasureDiggingTool.ViewModels;

public partial class FloorInfoViewModel : ObservableObject, INavigationAware
{
    private readonly ApplicationContext _dbContext;
    private readonly ISnackbarControl _snackbarControl;
    private readonly IDialogControl _dialogControl;

    private bool _isInitialized;

    [ObservableProperty]
    private string _routeContent;

    [ObservableProperty]
    private string _importString;

    private CustomRule _selectedRule;

    public CustomRule SelectedRule
    {
        get => _selectedRule;
        set
        {
            if (value is null)
            {
                _selectedRule = new CustomRule();
            }
            else
            {
                var newFloorInfos = value.FloorInfos.OrderBy(f => f.FloorNum).ToList();
                value.FloorInfos = newFloorInfos;
                _selectedRule = value;
            }

            OnPropertyChanged();
        }
    }

    private ObservableCollection<CustomRule> _customRules;

    public ObservableCollection<CustomRule> CustomRules
    {
        get => _customRules;
        set => SetProperty(ref _customRules, value);
    }

    [ObservableProperty]
    private FloorInfo _selectedFloorInfo;

    [ObservableProperty]
    private bool _isLeftChecked;

    [ObservableProperty]
    private bool _isRightChecked;

    public FloorInfoViewModel(
        ApplicationContext dbContext,
        ISnackbarService snackbarService,
        IDialogService dialogService
    )
    {
        _dbContext = dbContext;
        _snackbarControl = snackbarService.GetSnackbarControl();
        _dialogControl = dialogService.GetDialogControl();
    }

    public void OnNavigatedTo()
    {
        if (!_isInitialized)
        {
            InitializeViewlModel();
        }
    }

    public void OnNavigatedFrom()
    { }

    private void InitializeViewlModel()
    {
        _dialogControl.DialogHeight = 190;
        _dialogControl.ButtonRightClick += DialogControlOnButtonRightClick;
        _dialogControl.ButtonLeftClick += DialogControlOnButtonRightClick;
        CustomRules = new ObservableCollection<CustomRule>(
            _dbContext.CustomRules
                .Include(r => r.FloorInfos)
                .ThenInclude(f => f.RouteOptions)
                .Include(c => c.TotalEvents)
                .ToList()
        );
        SelectedRule = CustomRules.First();
        SelectedFloorInfo = new FloorInfo()
        {
            FloorNum = -1,
            RouteOptions = new List<RouteOption>()
        };
        RouteContent = string.Empty;
        ImportString = string.Empty;
    }

    [RelayCommand]
    public void AddCustomRule()
    {
        var newRule = new CustomRule()
        {
            Id = Guid.NewGuid(),
            RuleName = $"新规则{GenerateCheckCode(5)}",
            IsCurrentRule = false
        };
        CustomRules.Add(newRule);

        SelectedRule = CustomRules.Single(c => c.Id == newRule.Id);
    }

    [RelayCommand]
    public void AddFloorInfo()
    {
        var newFloorInfo = new FloorInfo() { RouteOptions = new List<RouteOption>() };
        if (SelectedRule.FloorInfos.Count >= 6)
        {
            _snackbarControl.Show("新增楼层失败", "当前规则层数已大于等于6");
            return;
        }

        newFloorInfo.FloorNum = SelectedRule.FloorInfos.Count + 1;
        SelectedRule.FloorInfos.Add(newFloorInfo);
        SelectedRule = SelectedRule;
    }

    [RelayCommand]
    public void AddRouteOption()
    {
        if (SelectedFloorInfo.FloorNum < 1)
        {
            _snackbarControl.Show("新增选项失败", "没有选择楼层");
            return;
        }

        if (string.IsNullOrEmpty(RouteContent))
        {
            _snackbarControl.Show("新增选项失败", "添加的选项的内容为空");
            return;
        }

        if (!IsLeftChecked && !IsRightChecked)
        {
            _snackbarControl.Show("新增选项失败", "没有选择对应的门");
            return;
        }

        var routeOption = new RouteOption();
        routeOption.EnemyType = RouteContent;
        routeOption.DoorPosition = IsLeftChecked ? DoorPosition.左 : DoorPosition.右;
        SelectedFloorInfo.RouteOptions.Add(routeOption);
        SelectedRule = SelectedRule;
    }

    [RelayCommand]
    public async void DeleteRule()
    {
        var button = await _dialogControl.ShowAndWaitAsync("注意", "是否删除该规则？", true);

        if (SelectedRule.Id.ToString().ToUpper() == "212381D1-8DA1-4BA9-B560-51CF1AD62A5C")
        {
            _snackbarControl.Show("删除失败", "默认规则不能删除");
            return;
        }

        var toDeleteRule = _dbContext.CustomRules.SingleOrDefault(c => c.Id == SelectedRule.Id);

        if (button == IDialogControl.ButtonPressed.Right)
        {
            if (toDeleteRule is null)
            {
                _snackbarControl.Show("删除失败", "选择的规则不存在于数据库中");
                return;
            }

            _dbContext.CustomRules.Remove(toDeleteRule);
            _dbContext.SaveChanges();

            CustomRules = new ObservableCollection<CustomRule>(
                _dbContext.CustomRules
                    .Include(r => r.FloorInfos)
                    .ThenInclude(f => f.RouteOptions)
                    .Include(c => c.TotalEvents)
                    .ToList()
            );
            SelectedRule = CustomRules.First();
        }
    }

    [RelayCommand]
    public void CopyRule()
    {
        var newRule = JsonSerializer.Deserialize<CustomRule>(
            JsonSerializer.Serialize(
                SelectedRule,
                new JsonSerializerOptions
                {
                    Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
                    WriteIndented = true,
                    ReferenceHandler = ReferenceHandler.IgnoreCycles
                }
            )
        );
        newRule.Id = Guid.NewGuid();
        newRule.RuleName = $"复制的{SelectedRule.RuleName}{GenerateCheckCode(5)}";
        newRule.IsCurrentRule = false;
        CustomRules.Add(newRule);
        CustomRules = CustomRules;

        _snackbarControl.Show("已新增", "请在下拉框选择新增的规则进行编辑");
    }

    [RelayCommand]
    public void ExportRule()
    {
        string exportString = JsonSerializer.Serialize(
            SelectedRule,
            new JsonSerializerOptions
            {
                Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
                WriteIndented = true,
                ReferenceHandler = ReferenceHandler.IgnoreCycles
            }
        );
        var exportCode = EncodeBase64("utf-8", exportString);
        Clipboard.SetText(exportCode);
        _snackbarControl.Show("已将导出代码复制到粘贴板", "");
    }

    [RelayCommand]
    public void ImportRule()
    {
        try
        {
            if (!string.IsNullOrEmpty(ImportString))
            {
                var newRule = JsonSerializer.Deserialize<CustomRule>(
                    DecodeBase64("utf-8", ImportString)
                );
                newRule.Id = Guid.NewGuid();
                newRule.RuleName = "导入的" + newRule.RuleName + GenerateCheckCode(5);
                newRule.IsCurrentRule = false;
                CustomRules.Add(newRule);
                CustomRules = CustomRules;

                _snackbarControl.Show("已导入", "请在下拉框选择导入的规则进行编辑");
            }
        }
        catch (Exception e)
        {
            _snackbarControl.Show("导入失败", e.Message);
        }
    }

    [RelayCommand]
    public void SaveEdit()
    {
        var rule = _dbContext.CustomRules.SingleOrDefault(c => c.Id == SelectedRule.Id);
        if (rule is not null)
        {
            _dbContext.Update(rule);
            _dbContext.SaveChanges();
            _snackbarControl.Show("修改保存成功", "");

            CustomRules = new ObservableCollection<CustomRule>(
                _dbContext.CustomRules
                    .Include(r => r.FloorInfos)
                    .ThenInclude(f => f.RouteOptions)
                    .Include(c => c.TotalEvents)
                    .ToList()
            );
            SelectedRule = CustomRules.First();

            return;
        }

        _dbContext.CustomRules.Add(SelectedRule);
        _dbContext.SaveChanges();
        _snackbarControl.Show("新增保存成功", "");

        CustomRules = new ObservableCollection<CustomRule>(
            _dbContext.CustomRules
                .Include(r => r.FloorInfos)
                .ThenInclude(f => f.RouteOptions)
                .Include(c => c.TotalEvents)
                .ToList()
        );
        SelectedRule = CustomRules.First();
    }

    [RelayCommand]
    public void RemoveRouteOption(RouteOption routeOption)
    {
        if (SelectedFloorInfo.FloorNum < 0)
        {
            _snackbarControl.Show("请选中楼层后再点击移除按钮", "");
            return;
        }

        if (SelectedFloorInfo.RouteOptions is null)
        {
            _snackbarControl.Show("移除失败，选中的楼层没有选项", "");
            return;
        }

        if (!SelectedFloorInfo.RouteOptions.Contains(routeOption))
        {
            _snackbarControl.Show("移除失败，要移除的选项不在选中的楼层", "");
            return;
        }

        SelectedFloorInfo.RouteOptions.Remove(routeOption);
        SelectedRule = SelectedRule;
    }

    private static void DialogControlOnButtonRightClick(object sender, RoutedEventArgs e)
    {
        var dialogControl = (IDialogControl)sender;
        dialogControl.Hide();
    }

    private int rep = 0;

    private string GenerateCheckCode(int codeCount)
    {
        string str = string.Empty;
        long num2 = DateTime.Now.Ticks + this.rep;
        this.rep++;
        Random random = new Random(
            ((int)(((ulong)num2) & 0xffffffffL)) | ((int)(num2 >> this.rep))
        );
        for (int i = 0; i < codeCount; i++)
        {
            char ch;
            int num = random.Next();
            if ((num % 2) == 0)
            {
                ch = (char)(0x30 + ((ushort)(num % 10)));
            }
            else
            {
                ch = (char)(0x41 + ((ushort)(num % 0x1a)));
            }

            str = str + ch.ToString();
        }

        rep = 0;
        return str;
    }

    ///编码
    public static string EncodeBase64(string code_type, string code)
    {
        string encode = "";
        byte[] bytes = Encoding.GetEncoding(code_type).GetBytes(code);
        try
        {
            encode = Convert.ToBase64String(bytes);
        }
        catch
        {
            encode = code;
        }

        return encode;
    }

    ///解码
    public static string DecodeBase64(string code_type, string code)
    {
        string decode = "";
        byte[] bytes = Convert.FromBase64String(code);
        try
        {
            decode = Encoding.GetEncoding(code_type).GetString(bytes);
        }
        catch
        {
            decode = code;
        }

        return decode;
    }
}